﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using ProLinq.Toolkit;

namespace ProLinq.Tests.Toolkit
{
	[TestClass]
	public class TypeExtensionsTests
	{
		#region Is

		[TestMethod]
		public void Is_ReturnsFalseForDifferentType()
		{
			Type t1 = typeof (Int32);
			Type t2 = typeof (Decimal);

			Assert.IsFalse(t1.Is(t2));
		}

		[TestMethod]
		public void Is_ReturnsTrueForSameType()
		{
			Type t1 = typeof (Int32);
			Type t2 = typeof (Int32);

			Assert.IsTrue(t1.Is(t2));
		}

		[TestMethod]
		public void Is_ReturnsTrueForSameGenericDefinitionType()
		{
			Type t1 = typeof (List<Int32>);
			Type t2 = typeof (List<>);

			Assert.IsTrue(t1.Is(t2));
		}


		[TestMethod]
		public void Is_ReturnsTrueForImplementedInterface()
		{
			Type t1 = typeof (List<Int32>);
			Type t2 = typeof (IEnumerable<Int32>);

			Assert.IsTrue(t1.Is(t2));
		}

		[TestMethod]
		public void Is_ReturnsTrueForImplementedInterfaceGenericDefinition()
		{
			Type t1 = typeof (List<Int32>);
			Type t2 = typeof (IEnumerable<>);

			Assert.IsTrue(t1.Is(t2));
		}


		[TestMethod]
		public void Is_ReturnsTrueForImplementedInterfaceGenericDefinitionOfGenericDefinition()
		{
			Type t1 = typeof (List<>);
			Type t2 = typeof (IEnumerable<>);

			Assert.IsTrue(t1.Is(t2));
		}

		[TestMethod]
		public void Is_ReturnsTrueForBaseType()
		{
			Type t1 = typeof (ObservableCollection<Int32>);
			Type t2 = typeof (Collection<Int32>);

			Assert.IsTrue(t1.Is(t2));
		}

		[TestMethod]
		public void Is_ReturnsTrueForBaseGenericDefinitionType()
		{
			Type t1 = typeof (ObservableCollection<Int32>);
			Type t2 = typeof (Collection<>);

			Assert.IsTrue(t1.Is(t2));
		}


		[TestMethod]
		public void Is_ReturnsTrueForBaseGenericDefinitionTypeOfGenericDefinition()
		{
			Type t1 = typeof (ObservableCollection<>);
			Type t2 = typeof (Collection<>);

			Assert.IsTrue(t1.Is(t2));
		}

		#endregion

		#region IsAnonymousType

		[TestMethod]
		public void IsAnonymousType_ReturnsFalseForNormalType()
		{
			Type t1 = typeof (List<Int32>);

			Assert.IsFalse(t1.IsAnonymousType());
		}

		[TestMethod]
		public void IsAnonymousType_ReturnsTrueForAnonymousType()
		{
			var t = new
				{
					Prop1 = "Abc"
				};

			Assert.IsTrue(t.GetType().IsAnonymousType());
		}

		#endregion


		#region IsAnonymousType

		[TestMethod]
		public void IsEnumerable_ReturnsTrueForEnumerable()
		{
			Type t1 = typeof(List<Int32>);

			Assert.IsTrue(t1.IsEnumerable());
		}

		[TestMethod]
		public void IsEnumerable_ReturnsFalseString()
		{
			Type t1 = typeof(String);

			Assert.IsFalse(t1.IsEnumerable());
		}

		#endregion

		#region GetEnumerableType

		[TestMethod]
		public void GetEnumerableType_ReturnsValidTypeForGenericEnumerableType()
		{
			Type t1 = typeof (List<Int32>);

			Assert.AreEqual(typeof (Int32), t1.GetEnumerableType());
		}

		[TestMethod]
		public void GetEnumerableType_ReturnsValidTypeForGenericEnumerableInterface()
		{
			Type t1 = typeof (IEnumerable<Int32>);

			Assert.AreEqual(typeof (Int32), t1.GetEnumerableType());
		}

		[TestMethod]
		public void GetEnumerableType_ReturnsValidTypeForGenericInheritedEnumerableInterface()
		{
			Type t1 = typeof(IList<Int32>);

			Assert.AreEqual(typeof(Int32), t1.GetEnumerableType());
		}

		[TestMethod]
		public void GetEnumerableType_ReturnsObjectForNonGenericEnumerableType()
		{
			Type t1 = typeof (Array);

			Assert.AreEqual(typeof (Object), t1.GetEnumerableType());
		}

		[TestMethod]
		public void GetEnumerableType_ReturnsObjectForNonGenericEnumerableInterface()
		{
			Type t1 = typeof (IEnumerable);

			Assert.AreEqual(typeof (Object), t1.GetEnumerableType());
		}

		[TestMethod]
		public void GetEnumerableType_ThrowsExceptionForNonEnumerableType()
		{
			Type t1 = typeof (Int32);

			try
			{
				t1.GetEnumerableType();
				Assert.Fail("Should have thrown an exception.");
			}
			catch (Exception)
			{

			}
		}

		#endregion


	}
}
